type Hour =
    | 0
    | 1
    | 2
    | 3
    | 4
    | 5
    | 6
    | 7
    | 8
    | 9
    | 10
    | 11
    | 12
    | 13
    | 14
    | 15
    | 16
    | 17
    | 18
    | 19
    | 20
    | 21
    | 22
    | 23;

type Minute =
    | "00"
    | "01"
    | "02"
    | "03"
    | "04"
    | "05"
    | "06"
    | "07"
    | "08"
    | "09"
    | 10
    | 11
    | 12
    | 13
    | 14
    | 15
    | 16
    | 17
    | 18
    | 19
    | 20
    | 21
    | 22
    | 23
    | 24
    | 25
    | 26
    | 27
    | 28
    | 29
    | 30
    | 31
    | 32
    | 33
    | 34
    | 35
    | 36
    | 37
    | 38
    | 39
    | 40
    | 41
    | 42
    | 43
    | 44
    | 45
    | 46
    | 47
    | 48
    | 49
    | 50
    | 51
    | 52
    | 53
    | 54
    | 55
    | 56
    | 57
    | 58
    | 59;

type Second =
    | ""
    | ":00"
    | ":01"
    | ":02"
    | ":03"
    | ":04"
    | ":05"
    | ":06"
    | ":07"
    | ":08"
    | ":09"
    | ":10"
    | ":11"
    | ":12"
    | ":13"
    | ":14"
    | ":15"
    | ":16"
    | ":17"
    | ":18"
    | ":19"
    | ":20"
    | ":21"
    | ":22"
    | ":23"
    | ":24"
    | ":25"
    | ":26"
    | ":27"
    | ":28"
    | ":29"
    | ":30"
    | ":31"
    | ":32"
    | ":33"
    | ":34"
    | ":35"
    | ":36"
    | ":37"
    | ":38"
    | ":39"
    | ":40"
    | ":41"
    | ":42"
    | ":43"
    | ":44"
    | ":45"
    | ":46"
    | ":47"
    | ":48"
    | ":49"
    | ":50"
    | ":51"
    | ":52"
    | ":53"
    | ":54"
    | ":55"
    | ":56"
    | ":57"
    | ":58"
    | ":59";

type TimePointTemplate = `${Hour}:${Minute}`;

class TimePoint {
    hour: number = 0;
    minute: number = 0;
    second: number = 0;

    constructor(hour: number, minute: number = 0, second: number = 0) {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }

    static compare(tp1: TimePoint, tp2: TimePoint): number {
        if (tp1.hour < tp2.hour) {
            return -1;
        } else if (tp1.hour > tp2.hour) {
            return 1;
        } else if (tp1.minute < tp2.minute) {
            return -1;
        } else if (tp1.minute > tp2.minute) {
            return 1;
        } else if (tp1.second < tp2.second) {
            return -1;
        } else if (tp1.second > tp2.second) {
            return 1;
        } else {
            return 0;
        }
    }

    // 减法操作，返回tp1和tp2的差值，以秒为单位
    static subtract(tp1: TimePoint, tp2: TimePoint): number {
        return (
            tp1.hour * 3600 +
            tp1.minute * 60 +
            tp1.second -
            (tp2.hour * 3600 + tp2.minute * 60 + tp2.second)
        );
    }
}

const timePointReg = /\d{1,2}:\d{2}(:\d{2})?/;

type DayOfWeekNum = 0 | 1 | 2 | 3 | 4 | 5 | 6;

type DayOfWeek =
    | "monday"
    | "tuesday"
    | "wednesday"
    | "thursday"
    | "friday"
    | "saturday"
    | "sunday";

type DayOfWeek2Num = { [_ in DayOfWeek]: DayOfWeekNum };

const day2num: DayOfWeek2Num = {
    sunday: 0,
    monday: 1,
    tuesday: 2,
    wednesday: 3,
    thursday: 4,
    friday: 5,
    saturday: 6,
};

function dayRange(start: DayOfWeek, end: DayOfWeek): DayOfWeekNum[] {
    let i: DayOfWeekNum = day2num[start];
    let j: DayOfWeekNum = day2num[end];

    let nums: DayOfWeekNum[] = [i, j];

    while (true) {
        i = ((i + 1) % 7) as DayOfWeekNum;
        if (i == j) {
            break;
        }

        nums.push(i);
    }

    return nums;
}

export {
    TimePointTemplate,
    TimePoint,
    timePointReg,
    DayOfWeekNum,
    DayOfWeek,
    day2num,
    dayRange,
};
